#============================================================================
# Python defaults setup for 'xm create'.
# Edit this file to reflect the configuration of your system.
-# This file expects the variable 'vmid' to be set.
#============================================================================
-def config_usage ():
- print >>sys.stderr,"""
-The config file '%s' requires the following variable to be defined:
- vmid -- Numeric identifier for the new domain, used to calculate
- the VM's IP address and root partition. E.g. -Dvmid=1
-""" % config_file
+# Define script variables here.
+# xm_vars is defined automatically, use xm_vars.var() to define a variable.
+def vmid_check(var, val):
+ val = int(val)
+ if val <= 0:
+ raise ValueError
+ return val
+
+xm_vars.var('vmid',
+ use="Virtual machine id. Integer greater than 0.",
+ check=vmid_check)
-try:
- vmid = int(vmid) # convert to integer
-except:
- raise ValueError, "Variable 'vmid' must be an integer"
-
-if vmid <= 0:
- raise ValueError, "Variable 'vmid' must be greater than 0"
+# This checks the script variables.
+xm_vars.check()
#----------------------------------------------------------------------------
# Kernel image file.
#----------------------------------------------------------------------------
# Set according to whether you want the domain restarted when it exits.
# The default is False.
-#restart = True
+#autorestart = True
#============================================================================
Needs to be persistent for one uptime.
"""
import sys
+import traceback
from twisted.internet import defer
+from twisted.internet import reactor
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
class XendDomain:
"""Index of all domains. Singleton.
"""
-
+
+ """Path to domain database."""
dbpath = "domain"
+
+ """Table of domain info indexed by domain id."""
domain = {}
+ """Table of configs for domain restart, indexed by domain id."""
+ restarts = {}
+
+ """Table of delayed calls."""
+ schedule = {}
+
def __init__(self):
self.xconsole = XendConsole.instance()
# Table of domain info indexed by domain id.
print 'XendDomain> virq', val
self.reap()
+ def schedule_later(self, _delay, _name, _fn, *args):
+ """Schedule a function to be called later (if not already scheduled).
+
+ _delay delay in seconds
+ _name schedule name
+ _fn function
+ args arguments
+ """
+ if self.schedule.get(_name): return
+ self.schedule[_name] = reactor.callLater(_delay, _fn, *args)
+
+ def schedule_cancel(self, name):
+ """Cancel a scheduled function call.
+
+ name schedule name to cancel
+ """
+ callid = self.schedule.get(name)
+ if not callid:
+ return
+ if callid.active():
+ callid.cancel()
+ del self.schedule[name]
+
+ def reap_schedule(self, delay=0):
+ """Schedule reap to be called later.
+
+ delay delay in seconds
+ """
+ self.schedule_later(delay, 'reap', self.reap)
+
+ def reap_cancel(self):
+ """Cancel any scheduled reap.
+ """
+ self.schedule_cancel('reap')
+
+ def refresh_schedule(self, delay=0):
+ """Schedule refresh to be called later.
+
+ delay delay in seconds
+ """
+ self.schedule_later(delay, 'refresh', self.refresh)
+
+ def refresh_cancel(self):
+ """Cancel any scheduled refresh.
+ """
+ self.schedule_cancel('refresh')
+
def rm_all(self):
"""Remove all domain info. Used after reboot.
"""
"""Look for domains that have crashed or stopped.
Tidy them up.
"""
+ self.reap_cancel()
print 'XendDomain>reap>'
domlist = xc.domain_getinfo()
casualties = []
for d in casualties:
id = str(d['dom'])
print 'XendDomain>reap> died id=', id, d
- self.domain_destroy(id, refresh=0)
+ self.final_domain_destroy(id)
print 'XendDomain>reap<'
def refresh(self):
"""Refresh domain list from Xen.
"""
+ self.refresh_cancel()
+ print 'XendDomain>refresh>'
domlist = xc.domain_getinfo()
# Index the domlist by id.
# Add entries for any domains we don't know about.
d.update(dominfo)
else:
self._delete_domain(d.id)
- self.reap()
+ self.reap_schedule(1)
def refresh_domain(self, id):
"""Refresh information for a single domain.
"""Shutdown domain (nicely).
id domain id
- reason shutdown type: poweroff, reboot, halt
+ reason shutdown type: poweroff, reboot, suspend, halt
"""
dom = int(id)
if dom <= 0:
return 0
+ self.domain_restart_schedule(id, reason)
eserver.inject('xend.domain.shutdown', [id, reason])
+ if reason == 'halt':
+ reason = 'poweroff'
val = xend.domain_shutdown(dom, reason)
- self.refresh()
+ self.refresh_schedule()
return val
-
- def domain_destroy(self, id, refresh=1):
- """Terminate domain immediately.
+
+ def domain_restart_schedule(self, id, reason):
+ """Schedule a restart for a domain if it needs one.
+
+ id domain id
+ reason shutdown reason
+ """
+ if id in self.restarts:
+ # Don't schedule if already there.
+ return
+ restart = 0
+ if reason in ['poweroff', 'reboot']:
+ dominfo = self.domain.get(id)
+ if dominfo and (dominfo.autorestart or reason == 'reboot'):
+ restart = 1
+ # Clear autorestart flag to avoid multiple restarts.
+ dominfo.autorestart = 0
+
+ if restart:
+ self.restarts[id] = dominfo.config
+
+ def domain_restart_cancel(self, id):
+ """Cancel any restart scheduled for a domain.
+
+ id domain id
+ """
+ dominfo = self.domain.get(id)
+ if dominfo:
+ dominfo.autorestart = 0
+ if id in self.restarts:
+ del self.restarts[id]
+
+ def domain_restarts(self):
+ """Execute any scheduled domain restarts for domains that have gone.
+ """
+ for id in self.restarts.keys():
+ if id in self.domain:
+ # Don't execute restart for domains still running.
+ continue
+ config = self.restarts[id]
+ # Remove it from the restarts.
+ del self.restarts[id]
+ try:
+ self.domain_create(config)
+ except:
+ print >>sys.stderr, "XendDomain> Exception restarting domain"
+ traceback.print_exc(sys.stderr)
+
+ def final_domain_destroy(self, id):
+ """Final destruction of a domain..
id domain id
- refresh send a domain destroy event if true
"""
dom = int(id)
if dom <= 0:
val = dominfo.destroy()
else:
val = xc.domain_destroy(dom=dom)
- if refresh: self.refresh()
return val
+ def domain_destroy(self, id):
+ """Terminate domain immediately.
+ Camcels any restart for the domain.
+
+ id domain id
+ """
+ self.domain_restart_cancel(id)
+ val = self.final_domain_destroy(id)
+ self.refresh_schedule()
+ return val
+
def domain_migrate(self, id, dst):
"""Start domain migration.
id domain id
"""
# Need a cancel too?
+ # Don't forget to cancel restart for it.
pass
def domain_save(self, id, dst, progress=0):
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
"""Domain shutdown.
"""
import string
gopts = Opts(use="""[options] [DOM]
-Shutdown one or more domains gracefully.""")
+Shutdown one or more domains gracefully.
+""")
gopts.opt('help', short='h',
fn=set_true, default=0,
fn=set_true, default=0,
use='Wait for shutdown to complete.')
-gopts.opt('norestart', short='n',
+gopts.opt('halt', short='H',
+ fn=set_true, default=0,
+ use='Shutdown without reboot.')
+
+gopts.opt('reboot', short='R',
fn=set_true, default=0,
- use='Prevent domain restart.')
+ use='Shutdown and reboot.')
-def shutdown(opts, doms, wait):
+def shutdown(opts, doms, mode, wait):
def domains():
return [ int(a) for a in server.xend_domains() ]
if doms == None: doms = domains()
if 0 in doms:
doms.remove(0)
for d in doms:
- server.xend_domain_shutdown(d)
+ server.xend_domain_shutdown(d, mode)
if wait:
while doms:
alive = domains()
time.sleep(1)
opts.info("All domains terminated")
+def shutdown_mode(opts):
+ mode = 'poweroff'
+ if opts.vals.wait:
+ mode = 'halt'
+ if opts.vals.reboot:
+ opts.err("Can't specify wait and reboot")
+ else:
+ if opts.vals.halt and opts.vals.reboot:
+ opts.err("Can't specify halt and reboot")
+ if opts.vals.halt:
+ mode = 'halt'
+ elif opts.vals.reboot:
+ mode = 'reboot'
+ return mode
+
def main_all(opts, args):
shutdown(opts, None, opts.vals.wait)
domid = int(dom)
except:
opts.err('Invalid domain: ' + dom)
- shutdown(opts, [ domid ], opts.vals.wait)
+
+ mode = shutdown_mode(opts)
+ shutdown(opts, [ domid ], mode, opts.vals.wait)
def main(argv):
opts = gopts